package com.fsnbigdata.web;
import com.fsnbigdata.domain.*;
import com.fsnbigdata.domain.dto.NamingPair4;
import com.fsnbigdata.domain.query.PlantConservationQueryDslBinder;
import com.fsnbigdata.domain.query.SpecimenQueryDslBinder;
import com.fsnbigdata.enums.ResultEnum;
import com.fsnbigdata.exception.ParamException;
import com.fsnbigdata.service.api.DocumentService;
import com.fsnbigdata.service.api.HintService;
import com.fsnbigdata.util.ReflectUtil;
import com.fsnbigdata.util.SortTools;
import com.querydsl.core.types.Predicate;
import io.swagger.annotations.*;

import java.lang.reflect.Method;
import java.util.*;

import io.swagger.models.auth.In;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.querydsl.binding.QuerydslPredicate;
import org.springframework.roo.addon.web.mvc.controller.annotations.ControllerType;
import org.springframework.roo.addon.web.mvc.controller.annotations.RooController;
import org.springframework.roo.addon.web.mvc.controller.annotations.responses.json.RooJSON;
import com.fsnbigdata.service.api.SpecimenService;
import io.springlets.data.domain.GlobalSearch;

import java.security.Principal;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import org.springframework.web.util.UriComponents;
import springfox.documentation.annotations.ApiIgnore;

/**
 * = SpecimensCollectionJsonController
 *
 * TODO Auto-generated class documentation
 *
 */
@RooController(entity = Specimen.class, pathPrefix = "/api", type = ControllerType.COLLECTION)
@RooJSON
@RestController
@RequestMapping(value = "/api/specimens", name = "SpecimensCollectionJsonController", produces = MediaType.APPLICATION_JSON_VALUE)
@Api(tags = "Specimen", description = "标本" )
public class SpecimensCollectionJsonController {

    /**
     * TODO Auto-generated attribute documentation
     *
             */
    private SpecimenService specimenService;

    private DocumentService documentService;

    @Autowired
    private HintService hintService;

    /**
     * TODO Auto-generated constructor documentation
     *
     * @param specimenService
     */
    @Autowired
    public SpecimensCollectionJsonController(SpecimenService specimenService, DocumentService documentService) {
        this.specimenService = specimenService;
        this.documentService = documentService;
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @return SpecimenService
     */
    public SpecimenService getSpecimenService() {
        return specimenService;
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param specimenService
     */
    public void setSpecimenService(SpecimenService specimenService) {
        this.specimenService = specimenService;
    }

    public DocumentService getDocumentService() {
        return documentService;
    }

    public void setDocumentService(DocumentService documentService) {
        this.documentService = documentService;
    }

    @GetMapping(name = "index", value = "index")
    public ResponseEntity<List<NamingPair4>> category(
        @ApiParam @RequestParam(required = false) String initial,
        @RequestParam(required = false) String name,
        @RequestParam(required = false) String value) {
        List<NamingPair4> namingPairs = getSpecimenService().findAllByInitial(name,value,initial);
        return ResponseEntity.ok(namingPairs);
    }

    /**
     * 根据类型查找数据
     */
    @GetMapping(name = "search", value = "show")
    public List<List<Specimen>> show(
            @RequestParam(required = false) String search) {
        //返回全部数据

        return getSpecimenService().findAllByType();

    }

    /*** 自定义搜索
     * @param
     * @param
     * @param pageable
     * @return
     */
//    @GetMapping(name = "search", value = "customSearch")
//    @ApiImplicitParams({
//            @ApiImplicitParam(name = "page", defaultValue = "0", dataType = "int", paramType = "query"),
//            @ApiImplicitParam(name = "size", defaultValue = "20", dataType = "int", paramType = "query")
//    })
//    public Page<Specimen> getList(org.apache.catalina.servlet4preview.http.HttpServletRequest request, Pageable pageable){
//        String name = request.getParameter("name");//关键字
//        String content = request.getParameter("content");//desc或asc
//        String value = request.getParameter("value");//字段名称
//        String type = request.getParameter("type");//类型
//        String creator = request.getParameter("creator");//创建人
//        String collectDate = request.getParameter("collectDate");//采集时间
//        String collectLocation = request.getParameter("collectLocation");//采集地
//
//
//        Page<Specimen> specimens=null;
//        if (StringUtils.isNotEmpty(content)&&StringUtils.isNotEmpty(value)){
//            Pageable pageable1=new PageRequest(pageable.getPageNumber(),pageable.getPageSize(),SortTools.basicSort(content,value));
//            specimens=getSpecimenService().findByPageAndSize(type==null||"".equals(type)?null:Integer.valueOf(type),creator,name,collectDate,collectLocation,pageable1);
//        }else{
//            specimens=getSpecimenService().findByPageAndSize(type==null||"".equals(type)?null:Integer.valueOf(type),creator,name,collectDate,collectLocation,pageable);
//        }
//        return specimens;
//    }
    /**
     * 根据分类查询数量
     * @param type
     * @return
     */
    @GetMapping(name = "count", value = "count")
    public  Map<String, Integer> count(String type){
        Map<String, Integer> map = new HashMap<String, Integer>();
        List<Specimen> specimenList=getSpecimenService().findAllByType(Integer.valueOf(type));
        map.put("specimenCount", specimenList.size()); //物种
        return map;

    }
    /**
     * TODO Auto-generated method documentation
     *
     * @param query
     * @param pageable
     * @return ResponseEntity
     */
    @GetMapping(name = "search", value = "search")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", defaultValue = "0", dataType = "int", paramType = "query"),
            @ApiImplicitParam(name = "size", defaultValue = "20", dataType = "int", paramType = "query")
    })
    public ResponseEntity<Page<Specimen>> search(
            @ApiParam @RequestParam(required = false)  String query,
            Pageable pageable,
            @RequestParam(required = false) String name,
            @RequestParam(required = false) String value) {
        GlobalSearch globalSearch = StringUtils.isNotBlank(query) ? new GlobalSearch(query, false) : null;
        Page<Specimen> specimens=null;
        if (StringUtils.isNotEmpty(name)&&StringUtils.isNotEmpty(value)){
            Pageable pageable1=new PageRequest(pageable.getPageNumber(),pageable.getPageSize(),SortTools.basicSort(name,value));
            specimens = getSpecimenService().findAll(globalSearch, pageable1);
        }else{
            specimens = getSpecimenService().findAll(globalSearch, pageable);
        }
        return ResponseEntity.ok(specimens);
    }

    /**
     *
     * @param predicate
     * @param pageable
     * @return
     */
    @GetMapping(name = "search", value = "advanceSearch")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", defaultValue = "0", dataType = "int", paramType = "query"),
            @ApiImplicitParam(name = "size", defaultValue = "20", dataType = "int", paramType = "query")
    })
    public ResponseEntity<Page<Specimen>> advanceSearch(
            @ApiParam @QuerydslPredicate(root = Specimen.class, bindings = SpecimenQueryDslBinder.class) Predicate predicate,
            Pageable pageable) {
        Page<Specimen> specimens=getSpecimenService().search(predicate, pageable);
        return ResponseEntity.ok(specimens);
    }

    /*** 自定义搜索
     * @param
     * @param
     * @param pageable
     * @return
     */
    @GetMapping(name = "search", value = "customSearch")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", defaultValue = "0", dataType = "int", paramType = "query"),
            @ApiImplicitParam(name = "size", defaultValue = "20", dataType = "int", paramType = "query")
    })
    public List searchPageList(HttpServletRequest request,Pageable pageable){
        String content = request.getParameter("content");//desc或asc
        String value = request.getParameter("value");//字段名称
        String name = request.getParameter( "name" );
        String status= request.getParameter( "status" );
        String collectNumber= request.getParameter( "collectNumber" );
        String collectPerson= request.getParameter( "collectPerson" );
        String type= request.getParameter( "type" );
        String collectDate= request.getParameter( "collectDate" );
        String collectLocation= request.getParameter( "collectLocation" );

        if (StringUtils.isNotEmpty(content)&&StringUtils.isNotEmpty(value)){
            Pageable pageable1=new PageRequest(pageable.getPageNumber(),pageable.getPageSize(), SortTools.basicSort(content,value));
            return specimenService.searchPageList(name,status,collectNumber,collectPerson,type,collectDate,collectLocation,pageable1);
        }else{
            return specimenService.searchPageList(name,status,collectNumber,collectPerson,type,collectDate,collectLocation,pageable);
        }
    }

    /**
     * 根据id 降序排序
     */
    @GetMapping(name = "search", value = "sortByIdAndDesc")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", defaultValue = "0", dataType = "int", paramType = "query"),
            @ApiImplicitParam(name = "size", defaultValue = "20", dataType = "int", paramType = "query")
    })
    public ResponseEntity<Page<Specimen>> sortByIdAndDesc(
            @ApiParam @QuerydslPredicate(root = Specimen.class, bindings = SpecimenQueryDslBinder.class) Predicate predicate,
            Pageable pageable) {
        Pageable pageable1=new PageRequest(pageable.getPageNumber(),pageable.getPageSize(),SortTools.basicSort("DESC","id"));
        Page<Specimen> specimens=getSpecimenService().search(predicate, pageable1);
        return ResponseEntity.ok(specimens);
    }
    /**
     * 根据id 升序排序
     */

    @GetMapping(name = "search", value = "sortByIdAndAsc")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", defaultValue = "0", dataType = "int", paramType = "query"),
            @ApiImplicitParam(name = "size", defaultValue = "20", dataType = "int", paramType = "query")
    })
    public ResponseEntity<Page<Specimen>> sortByIdAndAsc(
            @ApiParam @QuerydslPredicate(root = Specimen.class, bindings = SpecimenQueryDslBinder.class) Predicate predicate,
            Pageable pageable) {
        Pageable pageable1=new PageRequest(pageable.getPageNumber(),pageable.getPageSize(),SortTools.basicSort("ASC","id"));
        Page<Specimen> specimens=getSpecimenService().search(predicate, pageable1);
        return ResponseEntity.ok(specimens);
    }



    /**
     * 根据 collectDate 升序排序
     *
     */
    @GetMapping(name = "search", value = "sortByCollectDateDesc")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", defaultValue = "0", dataType = "int", paramType = "query"),
            @ApiImplicitParam(name = "size", defaultValue = "20", dataType = "int", paramType = "query")
    })
    public ResponseEntity<Page<Specimen>> sortByCollectDateDesc(
            @ApiParam @QuerydslPredicate(root = Specimen.class, bindings = SpecimenQueryDslBinder.class) Predicate predicate,
            Pageable pageable) {
        Pageable pageable1=new PageRequest(pageable.getPageNumber(),pageable.getPageSize(),SortTools.basicSort("DESC","collectDate"));
        Page<Specimen> specimens=getSpecimenService().search(predicate, pageable1);
        return ResponseEntity.ok(specimens);
    }
    /**
     * 根据 collectDate 升序排序
     *
     */
    @GetMapping(name = "search", value = "sortByCollectDateAsc")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", defaultValue = "0", dataType = "int", paramType = "query"),
            @ApiImplicitParam(name = "size", defaultValue = "20", dataType = "int", paramType = "query")
    })
    public ResponseEntity<Page<Specimen>> sortByCollectDateAsc(
            @ApiParam @QuerydslPredicate(root = Specimen.class, bindings = SpecimenQueryDslBinder.class) Predicate predicate,
            Pageable pageable) {
        Pageable pageable1=new PageRequest(pageable.getPageNumber(),pageable.getPageSize(),SortTools.basicSort("ASC","collectDate"));
        Page<Specimen> specimens=getSpecimenService().search(predicate, pageable1);
        return ResponseEntity.ok(specimens);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param query
     * @param pageable
     * @return ResponseEntity
     */
    @GetMapping(name = "list")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", defaultValue = "0", dataType = "int", paramType = "query"),
            @ApiImplicitParam(name = "size", defaultValue = "20", dataType = "int", paramType = "query")
    })
    @PreAuthorize("hasRole('ROLE_DB_SPECIMEN')")
    public ResponseEntity<Page<Specimen>> list(
            Authentication authentication,
            @ApiParam @RequestParam(required = false)  String query,
            Pageable pageable) {
        Page<Specimen> specimens = null;
        GlobalSearch globalSearch = StringUtils.isNotBlank(query) ? new GlobalSearch(query, false) : null;
        List<String> authorities = authentication.getAuthorities().stream().map(it -> it.getAuthority()).collect(Collectors.toList());
        if(!authorities.contains("ROLE_USER_ADMIN")){
            specimens = getSpecimenService().findAll(globalSearch, pageable, authentication.getName());
        }else{
            specimens = getSpecimenService().findAll(globalSearch, pageable);
        }
        return ResponseEntity.ok(specimens);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @return UriComponents
     */
    public static UriComponents listURI() {
        return MvcUriComponentsBuilder.fromMethodCall(MvcUriComponentsBuilder.on(SpecimensCollectionJsonController.class).list(null, null, null)).build().encode();
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param specimen
     * @param result
     * @return ResponseEntity
     */
    @PostMapping(name = "create")
    @PreAuthorize("hasRole('DB_SPECIMEN')")
    @ApiOperation(value = "",notes = "save")
    public ResponseEntity<?> create(
            @Valid @RequestBody Specimen specimen,
            BindingResult result,
            Principal principal) throws Exception {
        if (specimen.getId() != null || specimen.getVersion() != null) {
            return ResponseEntity.status(HttpStatus.CONFLICT).build();
        }
        if (result.hasErrors()) {
            throw new ParamException(ResultEnum.PARAM_ERROR.getCode(),
                    result.getFieldError().getDefaultMessage());
        }

        specimen.setCreator(principal.getName());

        Set<Document> toSaveDocs = specimen.getDocs();
        specimen.setDocs(new HashSet<>());

        Specimen newSpecimen = getSpecimenService().save(specimen);

        Set<Long> docIds = toSaveDocs.stream().map(doc -> {
            if(doc.getId() == null) {
                doc.setCreator(principal.getName());
                getDocumentService().save(doc);
                return doc.getId();
            }else{
                return doc.getId();
            }
        }).collect(Collectors.toSet());

        getSpecimenService().setDocs(newSpecimen, docIds);
        Class<?> clazz = SpecimensCollectionJsonController.class;
        Method method = clazz.getMethod("create", ReflectUtil.getPeremeterClass(clazz, "create"));
        ReflectUtil.setAnnotationOn(method,"新增标本库，中文名："+newSpecimen.getName());
        //UriComponents showURI = OrganismsItemJsonController.showURI(newSpecimen);
        return ResponseEntity.ok(newSpecimen);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param specimens
     * @param result
     * @return ResponseEntity
     */
    @PostMapping(value = "/batch", name = "createBatch")
    @PreAuthorize("hasRole('DB_SPECIMEN')")
    @ApiIgnore
    public ResponseEntity<?> createBatch(@Valid @RequestBody Collection<Specimen> specimens, BindingResult result) {
        if (result.hasErrors()) {
            return ResponseEntity.status(HttpStatus.CONFLICT).body(result);
        }

        specimens.forEach(specimen -> specimen.getImages().forEach(it -> it.setSpecimen(specimen)));
        specimens.forEach(specimen -> specimen.getVideos().forEach(it -> it.setSpecimen(specimen)));
        specimens.forEach(specimen -> specimen.getDocuments().forEach(it -> it.setSpecimen(specimen)));

        getSpecimenService().save(specimens);
        return ResponseEntity.created(listURI().toUri()).build();
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param specimens
     * @param result
     * @return ResponseEntity
     */
    @PutMapping(value = "/batch", name = "updateBatch")
    @PreAuthorize("hasRole('DB_SPECIMEN')")
    @ApiIgnore
    public ResponseEntity<?> updateBatch(@Valid @RequestBody Collection<Specimen> specimens, BindingResult result) {
        if (result.hasErrors()) {
            return ResponseEntity.status(HttpStatus.CONFLICT).body(result);
        }

        specimens.forEach(specimen -> specimen.getImages().forEach(it -> it.setSpecimen(specimen)));
        specimens.forEach(specimen -> specimen.getVideos().forEach(it -> it.setSpecimen(specimen)));
        specimens.forEach(specimen -> specimen.getDocuments().forEach(it -> it.setSpecimen(specimen)));

        getSpecimenService().save(specimens);
        return ResponseEntity.ok().build();
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param ids
     * @return ResponseEntity
     */
    @DeleteMapping(value = "/batch/{ids}", name = "deleteBatch")
    @PreAuthorize("hasRole('DB_SPECIMEN')")
    @ApiIgnore
    public ResponseEntity<?> deleteBatch(@PathVariable("ids") Collection<Long> ids) {
        getSpecimenService().delete(ids);
        return ResponseEntity.ok().build();
    }

    /**
     * 根据id查询详情
     * @param request
     * @return
     */
    @GetMapping(name = "find" , value="find")
    public Specimen findById(HttpServletRequest request){
       return getSpecimenService().findOne(Long.parseLong(request.getParameter("id")));
    }

    /**
     * 根据物种id查分诶信息
     */

    @GetMapping(name = "find" , value="findByOrganismId")
    public Taxonomy findByOrganismId(String organismId){
        return hintService.findOne(Long.parseLong(organismId));
    }
}
